package com.tmt.im.service.interfaces.impl;

import com.alibaba.fastjson2.JSONObject;
import com.tmt.im.common.enums.ChatSessionType;
import com.tmt.im.common.pojo.ChatSessionMemberPoJo;
import com.tmt.im.common.pojo.ChatSessionPoJo;
import com.tmt.im.common.pojo.IMUserPoJo;
import com.tmt.im.service.config.beans.YunXinProperties;
import com.tmt.im.service.controller.vo.*;
import com.tmt.im.service.helper.IgniteQueryHelper;
import com.tmt.im.service.helper.OperationFailInfoHelper;
import com.tmt.im.service.interfaces.ISessionMemberManager;
import com.tmt.im.service.interfaces.IYunXinInterface;
import com.tmt.im.service.service.ChatSessionService;
import com.tmt.im.service.service.SessionMemberService;
import com.tmt.springboot.common.restful.ExecuteResult;
import com.tmt.springboot.common.restful.IExecuteResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.security.Principal;
import java.text.MessageFormat;
import java.util.*;

/**
 * @Description TODO
 * @Author wuyi
 * @Date 2024/8/30 15:43
 * @Version 1.0
 **/
@Slf4j
@Order(0)
public class YunXinSessionMemberManager_V9 implements ISessionMemberManager, ApplicationContextAware {

    private ChatSessionService sessionService;

    private SessionMemberService sessionMemberService;

    private IYunXinInterface iYunXinInterface;

    private YunXinProperties yunXinProperties;


    public List<ChatSessionDetailVo> getAllSession(Long creatorId, StringBuilder error) {
        //先到云信平台中创建群组。
        JSONObject jsonObject = iYunXinInterface.getAllInSession(creatorId, error);
        if (jsonObject == null) {
            return null;
        }

        //需要解散的群组ID与群主ID映射。
        Map<Long, Long> needDeletedSessionMap = new HashMap<>();
        IExecuteResult<List<ChatSessionPoJo>> result = sessionService.getAllInSession(creatorId, jsonObject, needDeletedSessionMap);
        if (result.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(result.getMsg());
            return null;
        }

        //如果云信平台中存在的群组但本地表中没有该群组，则删除之。
        if (!CollectionUtils.isEmpty(needDeletedSessionMap)) {
            for (Long sessionId : needDeletedSessionMap.keySet()) {
                Long ownerId = needDeletedSessionMap.get(sessionId);
                if (iYunXinInterface.deleteSession(ownerId, ChatSessionType.GROUP, sessionId, error)) {
                    log.info("成功删除本地不存在的云信聊天群组(ID={})", sessionId);
                } else {
                    log.info("删除本地不存在的云信聊天群组(ID={})失败: {}", sessionId, error.toString());
                }
            }
        }

        return sessionService.loadChatSessionDetailVos(creatorId, result.getData());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public JoinSessionResponse joinSession(Long currentUserId, JoinSessionRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("目标群组不存在", "" + request.getTid()));
            return null;
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        if (poJo.getJoinMode() == 2) {
            error.append("该群不允许任何人申请入群");
            return null;
        }

        //获取群的邀请配置参数.
        if (poJo.getInviteMode() == 0) {
            boolean isOwner = sessionService.isSessionOwner(currentUserId, poJo);
            boolean isManager = sessionService.isManager(currentUserId, poJo.getId());
            if (!isOwner && !isManager) {
                error.append("只有群主和管理员才能邀请其他人入群");
                return null;
            }
        }

        for (Long memberId : request.getMemberIds()) {
            ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(memberId, request.getTid());
            if (memberPoJo != null && memberPoJo.getCheckStatus() != 2) {
                IMUserPoJo userPoJo = sessionService.getUserCache().get(memberId);
                String msg = memberPoJo.getCheckStatus() == 0 ? MessageFormat.format("该用户【{0}】入群邀请正在审核中", userPoJo.getNickname())
                        : MessageFormat.format("用户【{0}】已经在群组中", userPoJo.getNickname());
                error.append(msg);
                return null;
            }
            if (sessionService.inBlackBill(request.getTid(), memberId)) {
                IMUserPoJo userPoJo = sessionService.getUserCache().get(memberId);
                error.append(MessageFormat.format("用户【{0}】在群组黑名单中", userPoJo.getNickname()));
                return null;
            }
        }

        ChatSessionMemberPoJo currentMember = sessionService.getSessionMemberBy(currentUserId, request.getTid());

        if (!StringUtils.hasText(request.getInviteMsg())) {
            request.setInviteMsg(yunXinProperties.getGroupInitParam().getInviteMsg());
        }

        List<OperationFailInfo> failInfos = null;
        if (poJo.getJoinMode() == 0 || currentMember.getRoleInSession() <= 2) {
            //默认不需要被邀请人同意，所以直接将人拉入群中。
            JSONObject jsonObject = iYunXinInterface.joinSession(currentUserId, poJo.getId(), type, poJo.getBeInvitedMode(),
                    request.getInviteMsg(), request.getMemberIds(), error);
            if (jsonObject == null) {
                return null;
            }
            failInfos = OperationFailInfoHelper.convertTo(jsonObject);
        }

        //创建用户受邀入群记录(受邀人尚未确认或默认同意)。
        IExecuteResult<JoinSessionResponse> response = sessionMemberService.joinSession(currentUserId, request, principal, failInfos);
        if (response.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(response.getMsg());
            return null;
        }
        return response.getData();
    }

    @Override
    public WaitingCheckInvitationResponse listInvitation(Long currentUserId, Long tid, int pageIndex,
                                                         int pageSize, Principal principal, StringBuilder error) {
        StringBuilder condition = new StringBuilder();
        List<Object> params = new ArrayList<>();
        if (tid != null) {
            ChatSessionPoJo poJo = sessionService.findById(tid);
            if (poJo == null) {
                error.append(MessageFormat.format("群组(ID={0})不存在", "" + tid));
                return null;
            }
            condition.append(" or sessionId = ?");
            params.add(tid);
        } else {
            String sql = MessageFormat.format("select * from {0} where checkStatus = 1 and roleInSession <= 2 and memberId = ?",
                    ChatSessionMemberPoJo.CACHE_NAME);
            List<ChatSessionMemberPoJo> memberPoJos = IgniteQueryHelper.findAllBy(sql, new Object[]{currentUserId}, ChatSessionMemberPoJo.class,
                    sessionMemberService.getSessionMemberCache());
            if (CollectionUtils.isEmpty(memberPoJos)) {
                error.append(MessageFormat.format("当前用户不是其所在群的群主或群管理员", "" + tid));
                return null;
            }
            for (ChatSessionMemberPoJo memberPoJo : memberPoJos) {
                condition.append(" or ").append("sessionId = ?");
                params.add(memberPoJo.getSessionId());
            }
        }

        String sql = MessageFormat.format("select count(*) from {0} where checkStatus = 0 and ({1})",
                ChatSessionMemberPoJo.CACHE_NAME, condition.substring(4));
        long total = IgniteQueryHelper.getCountBy(sql, params.toArray(), sessionMemberService.getSessionMemberCache());

        List<WaitingCheckMemberInfo> memberInfos = new ArrayList<>();
        if (total > 0) {
            sql = MessageFormat.format("select * from {0} where checkStatus = 0 and ({1}) order by createTime limit ?,?",
                    ChatSessionMemberPoJo.CACHE_NAME, condition.substring(4));
            params.add(pageIndex * pageSize);
            params.add(pageSize);
            List<ChatSessionMemberPoJo> memberPoJos = IgniteQueryHelper.findAllBy(sql, params.toArray(), ChatSessionMemberPoJo.class,
                    sessionMemberService.getSessionMemberCache());
            memberInfos = sessionService.getWaitingCheckMemberInfoBy(memberPoJos);
        }
        return new WaitingCheckInvitationResponse(tid, pageIndex, pageSize, (int) total, memberInfos);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean reviewInvitation(Long currentUserId, JoiningSessionReply reply, Principal principal, StringBuilder error) {
        ChatSessionMemberPoJo apply = sessionService.getSessionMemberBy(reply.getApplyId());
        if (apply == null) {
            error.append(MessageFormat.format("目标入群邀请记录不存在", "" + reply.getApplyId()));
            return false;
        }
        if (apply.getCheckStatus() != 0) {
            error.append(MessageFormat.format("目标入群邀请记录已经审核过了", "" + reply.getApplyId()));
            return false;
        }

        if (reply.isAgree()) {
            String inviteMsg = apply.getInviteMsg();
            if (!StringUtils.hasText(inviteMsg)) {
                inviteMsg = yunXinProperties.getGroupInitParam().getInviteMsg();
            }
            JSONObject jsonObject = iYunXinInterface.joinSession(apply.getCreatorId(), apply.getSessionId(), ChatSessionType.GROUP,
                    1, inviteMsg, List.of(apply.getMemberId()), error);
            if (jsonObject == null) {
                return false;
            }
        }

        //修改审核结果
        IExecuteResult<ChatSessionMemberPoJo> response = sessionMemberService.reviewInvitation(currentUserId, apply,
                reply.isAgree() ? 1 : 2, 1);
        if (response.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(response.getMsg());
            return false;
        }
        return true;
    }

    /**
     * 被邀请人同意或不同意入群
     *
     * @param currentUserId
     * @param reply
     * @param principal
     * @param error
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean replyInvitation(Long currentUserId, JoiningSessionReply reply, Principal principal, StringBuilder error) {
        ChatSessionMemberPoJo apply = sessionService.getSessionMemberBy(reply.getApplyId());
        if (apply == null) {
            error.append(MessageFormat.format("入群邀请ID(ID={0})不存在", "" + reply.getApplyId()));
            return false;
        }

        //修改审核结果
        IExecuteResult<ChatSessionMemberPoJo> response = sessionMemberService.replyInvitation(apply, reply.isAgree() ? 1 : 2);
        if (response.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(response.getMsg());
            return false;
        }

        //向群组发送人员入群通知.
        ChatSessionMemberPoJo smPojo = response.getData();
        sendCustomizedMessage(ChatSessionType.GROUP, smPojo, error);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public KickOutSessionResponse kickOutSession(Long currentUserId, KickOutSessionRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            error.append(MessageFormat.format("目标群组不存在", "" + request.getTid()));
            return null;
        }

        if (!Objects.equals(poJo.getOwnerId(), currentUserId) && !sessionService.isManager(currentUserId, request.getTid())) {
            error.append("当前用户不是群主或管理员");
            return null;
        }

        if (request.getMemberIds().contains(poJo.getOwnerId())) {
            error.append("不能踢出群主");
            return null;
        }

        for (Long memberId : request.getMemberIds()) {
            ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(memberId, request.getTid());
            if (memberPoJo == null) {
                error.append(MessageFormat.format("目标用户(id={0})不是目标群组的成员", "" + memberId));
                return null;
            }
        }

        JSONObject jsonObject = iYunXinInterface.kickOutSession(currentUserId, poJo.getId(), ChatSessionType.GROUP, request.getMemberIds(), error);
        if (jsonObject == null) {
            return null;
        }

        List<OperationFailInfo> failInfos = OperationFailInfoHelper.convertTo(jsonObject);

        IExecuteResult<KickOutSessionResponse> response = sessionMemberService.kickOutSession(currentUserId, request, principal, failInfos);
        if (response.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(response.getMsg());
            return null;
        }
        return response.getData();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean leaveSession(Long currentUserId, Long tid, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(tid);
        if (poJo == null) {
            error.append(MessageFormat.format("群组(Id={0})不存在", "" + tid));
            return false;
        }

        if (Objects.equals(poJo.getOwnerId(), currentUserId)) {
            error.append("您需要先转让群主后才能退出本群");
            return false;
        }

        ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(currentUserId, tid);
        if (memberPoJo == null) {
            error.append(MessageFormat.format("目标用户(id={0})不是目标群组的成员", "" + currentUserId));
            return false;
        }

        if (!iYunXinInterface.leaveSession(currentUserId, tid, ChatSessionType.GROUP, error)) {
            return false;
        }

        IExecuteResult<Boolean> result = sessionMemberService.leaveSession(currentUserId, tid, principal);
        if (result.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(result.getMsg());
            return false;
        }
        return true;
    }

    public IExecuteResult<Boolean> updateForbidRedPackage(Long currentUserId, UpdateForbidRedPackageRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()), false);
        }

        ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(currentUserId, request.getTid());
        if (memberPoJo == null || memberPoJo.getRoleInSession() == 3) {
            return ExecuteResult.failure("当前用户不是目标群组的群主或者管理员", false);
        }

        memberPoJo = sessionService.getSessionMemberBy(request.getMemberId(), request.getTid());
        if (memberPoJo == null) {
            return ExecuteResult.failure("目标用户不是群成员", false);
        }

        return sessionMemberService.updateForbidRedPackage(currentUserId, request, principal);
    }

    public IExecuteResult<Boolean> updateMemberNick(Long currentUserId, UpdateMemberNickRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()), false);
        }

        ChatSessionMemberPoJo memberPoJo = sessionService.getSessionMemberBy(currentUserId, request.getTid());
        if (memberPoJo == null
                || memberPoJo.getRoleInSession() == 3 && !Objects.equals(memberPoJo.getMemberId(), request.getMemberId())) {
            return ExecuteResult.failure("当前用户不是目标群组的群主或者管理员，并且也不是修改当前用户的群昵称", false);
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        if (!iYunXinInterface.updateMemberNick(currentUserId, poJo.getId(), type, request, error)) {
            return ExecuteResult.failure(error.toString(), false);
        }

        return sessionMemberService.updateMemberNick(currentUserId, request, principal);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public IExecuteResult<ChatBannedResponse> bannedMembers(Long currentUserId, ChatBannedRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()), null);
        }
        if (!Objects.equals(poJo.getOwnerId(), currentUserId)) {
            return ExecuteResult.failure("当前用户不是群主", null);
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        JSONObject jsonObject = iYunXinInterface.bannedMembers(currentUserId, poJo.getId(), type, request, error);
        if (jsonObject == null) {
            return ExecuteResult.failure(error.toString(), null);
        }

        List<OperationFailInfo> failInfos = OperationFailInfoHelper.convertTo(jsonObject);

        IExecuteResult<ChatBannedResponse> response = sessionMemberService.bannedMembers(currentUserId, request, principal, failInfos);
        if (response.getCode() != ExecuteResult.SUCCESS_CODE) {
            return ExecuteResult.failure(response.getMsg(), null);
        }
        return ExecuteResult.success(response.getData());
    }

    @Override
    public IExecuteResult<Boolean> noDisturbingMember(Long currentUserId, NoDisturbingRequest request, Principal principal, StringBuilder error) {
        ChatSessionPoJo poJo = sessionService.findById(request.getTid());
        if (poJo == null) {
            return ExecuteResult.failure(MessageFormat.format("群组ID(tid={0})不存在", "" + request.getTid()), null);
        }

        if (!sessionService.inSession(currentUserId, poJo)) {
            return ExecuteResult.failure("当前用户不在目标群组中", null);
        }

        ChatSessionType type = Arrays.stream(ChatSessionType.values())
                .filter(x -> x.name().equals(poJo.getType())).findFirst().orElse(null);
        assert type != null;

        if (!iYunXinInterface.noDisturbingMember(currentUserId, request.getTid(), type, request, error)) {
            return ExecuteResult.failure(error.toString(), null);
        }
        return sessionMemberService.noDisturbingMember(currentUserId, request, principal);
    }

    @Deprecated
    @Override
    public QueryGroupInfoResponse queryGroupList(Long currentUserId, int pageIndex, int pageSize,
                                                 Principal principal, StringBuilder error) {
        IExecuteResult<QueryGroupInfoResponse> response = sessionMemberService.queryGroupList(currentUserId, pageIndex, pageSize, principal);
        if (response.getCode() != ExecuteResult.SUCCESS_CODE) {
            error.append(response.getMsg());
            return null;
        }
        return response.getData();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        sessionService = applicationContext.getBean(ChatSessionService.class);
        sessionMemberService = applicationContext.getBean(SessionMemberService.class);
        iYunXinInterface = applicationContext.getBean(IYunXinInterface.class);
        yunXinProperties = applicationContext.getBean(YunXinProperties.class);
    }

    private boolean sendCustomizedMessage(ChatSessionType type, ChatSessionMemberPoJo smPojo, StringBuilder error) {
        if (smPojo.getAgreeStatus() == 1) {
            //向所有有效群成员发送通知.
            Map<String, Object> push_config = new LinkedHashMap<>();
            push_config.put("push_forcepush_all", true);
            //发送群消息: 某人将某人拉人了群聊.
            IMUserPoJo userPoJo = sessionService.getCurrentUser(smPojo.getCreatorId());
            IMUserPoJo userPoJo1 = sessionService.getCurrentUser(smPojo.getMemberId());
            String content = MessageFormat.format("{0}邀请{1}加入了群聊", userPoJo.getNickname(), userPoJo1.getNickname());
            return iYunXinInterface.sendCustomizedMessage(smPojo.getCreatorId(),
                    type.getType() + 1, smPojo.getSessionId(), content, null, null, push_config, error);
        }
        return false;
    }

}
